package com.liao.badminton.service.impl;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.liao.badminton.code.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liao.badminton.code.myenum.RoleCodeEnum;
import com.liao.badminton.code.util.CheckUtil;
import com.liao.badminton.code.util.EntityUtils;
import com.liao.badminton.code.util.JwtTokenUtils;
import com.liao.badminton.context.BaseContextHandler;
import com.liao.badminton.dto.*;
import com.liao.badminton.entity.BadmintonGroup;
import com.liao.badminton.entity.SystemLoginLog;
import com.liao.badminton.entity.SystemRole;
import com.liao.badminton.mapper.SystemUsersMapper;
import com.liao.badminton.redis.RedisEnum;
import com.liao.badminton.redis.RedisUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.liao.badminton.entity.SystemUsers;
import com.liao.badminton.service.*;
import com.liao.badminton.vo.SystemUsersVo;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Component;
import lombok.extern.log4j.Log4j2;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import static cn.hutool.core.bean.BeanUtil.isEmpty;
import static cn.hutool.core.util.ObjectUtil.isNotEmpty;
import static com.liao.badminton.code.RespCodeMessage.DB_DATA_EXIST;
import static com.liao.badminton.code.RespCodeMessage.DB_DATA_NULL;

/**
 * @author liaocheng
 * @date 2024-10-30
 * description:用户信息表
 */
@Component
@Log4j2
public class SystemUsersServiceImpl extends ServiceImpl<SystemUsersMapper, SystemUsers> implements SystemUsersService {
    @Resource
    private BadmintonGroupService groupService;
    @Resource
    private UserGroupRefService userGroupRefService;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private SystemUserRoleService systemUserRoleService;
    @Resource
    private SystemRoleService systemRoleService;


    /**
     * 新增
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Long> saveSystemUsers(SystemUsersDto param) throws ProjectException {
        SystemUsers systemUsers = param.invertEntity();
        EntityUtils.setCreatAndUpdateInfo(systemUsers);
        systemUsers.setLoginDate(new Date());
        this.save(systemUsers);
        return ResponseRest.suc("saveSystemUsers", systemUsers.getId());
    }

    /**
     * 删除
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Boolean> deletesSystemUsers(SystemUsersDto param) throws ProjectException {
        boolean bool = this.removeByIds(param.getDelIds());
        if (bool) {
            param.getDelIds().forEach(id -> RedisUtil.toDelete(RedisEnum.CACHE_TABLE_DATA, "systemUsers", "id", id));
        }
        return ResponseRest.suc("deletesSystemUsers");
    }

    /**
     * 修改
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 10, rollbackFor = Exception.class)
    public ResponseRest<Boolean> updateSystemUsers(SystemUsers param) throws ProjectException {
        SystemUsers systemUsers = param;
        EntityUtils.setUpdatedInfo(systemUsers);
        if (isNotEmpty(systemUsers.getPassword())) {
            systemUsers.setPassword(passwordEncoder.encode(systemUsers.getPassword()));
        }
        boolean bool = this.updateById(systemUsers);
        if (bool) {
            SystemUsers byId = this.getById(systemUsers.getId());
            RedisUtil.toDelete(RedisEnum.CACHE_TABLE_DATA, "systemUsers", "id", param.getId());
            RedisUtil.toDelete(RedisEnum.badminton_user_info_name, byId.getUsername());
            SystemUsersVo systemUsersVo = SystemUsersVo.invertToVo(byId);
//            systemUsersVo.setPassword(null);//密码不返回给前端
            RedisUtil.toSaveRedis(RedisEnum.badminton_user_info_name, systemUsersVo.getUsername(), systemUsersVo);
        }
        return ResponseRest.suc("updateSystemUsers", true);
    }

    /**
     * 查询列表
     */
    @Override
    public ResponseRest findSystemUsersByPageParam(PageParam<SystemUsersDto> pageParam) throws ProjectException {
        CheckUtil.checkValue(pageParam, "pageParam");
        ResponseRest resp = ResponseRest.suc("findSystemUsersByPageParam");
        PageHelper.startPage(pageParam.getCurrent(), pageParam.getSize());
        LambdaQueryWrapper<SystemUsers> query = new LambdaQueryWrapper<>();
        List<SystemUsers> list = this.list(query);
        List<SystemUsersVo> collect = list.stream().parallel().map(entity -> SystemUsersVo.invertToVo(entity)).collect(Collectors.toList());
        resp.setData(new PageInfo<>(collect));
        return resp;
    }

    /**
     * 查询详情
     */
    @Override
    public SystemUsersVo findDetail(SystemUsersDto param) throws ProjectException {
        if (isEmpty(param.getId())) {
            param.setId(BaseContextHandler.getCurrUserID());
        }
        Object getDate = RedisUtil.toGetDate(RedisEnum.CACHE_TABLE_DATA, "systemUsers", "id", param.getId());
        if (isNotEmpty(getDate)) {
            RedisUtil.toFlushExpire(RedisEnum.CACHE_TABLE_DATA, "systemUsers", "id", param.getId());
            return (SystemUsersVo) getDate;
        }
        SystemUsersVo vo = null;
        SystemUsers db = this.getById(param.getId());
        if (isNotEmpty(db)) {
            vo = SystemUsersVo.invertToVo(db);
            vo.setPassword(null);//密码不返回给前端
            RedisUtil.toSaveRedis(RedisEnum.CACHE_TABLE_DATA, "systemUsers", "id", param.getId(), vo, null);

        }
        return  vo;
    }


    @Override
    public SystemUsersVo findByName(String username) {
        SystemUsersVo userDetail = (SystemUsersVo) RedisUtil.toGetDate(RedisEnum.badminton_user_info_name, username);
        if (ObjectUtils.isNotEmpty(userDetail)) {
            return userDetail;
        }
        SystemUsers param = new SystemUsers();
        param.setUsername(username);
        QueryWrapper<SystemUsers> wrapper = new QueryWrapper();
        wrapper.eq("username", username);
        SystemUsers one = this.getOne(wrapper);
        if (one != null) {
            SystemUsersVo systemUsersVo = SystemUsersVo.invertToVo(one);
//            systemUsersVo.setPassword(null);//密码不返回给前端
            RedisUtil.toSaveRedis(RedisEnum.badminton_user_info_name, systemUsersVo.getUsername(), systemUsersVo);
            return systemUsersVo;
        }
        return null;
    }

    /**
     * @Description: register
     * @Param:
     * @return:
     * @Date: 2024/10/30
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 100, rollbackFor = Exception.class)
    public SystemUsersVo register(SystemUsersDto systemUsersDto, HttpServletResponse response) throws ProjectException {
        SystemUsersVo systemUsersVo = this.findByName(systemUsersDto.getUsername());
        try {
            if (isNotEmpty(systemUsersVo)) {
                ProjectException.newException(DB_DATA_EXIST, "用户已经注册");
            }
            SystemUsers systemUsers = systemUsersDto.invertEntity();
            systemUsers.setLoginDate(new Date());
            systemUsers.setPassword(passwordEncoder.encode(systemUsersDto.getPassword()));
            systemUsers.setUserCode(generateUserCode());
            EntityUtils.setCreatAndUpdateInfo(systemUsers);
            this.save(systemUsers);
            BaseContextHandler.setUserID(systemUsers.getId());
            systemUsersVo= SystemUsersVo.invertToVo(systemUsers);
            //用户和角色关系,先给群成员
            SystemRole role = systemRoleService.getOne(new QueryWrapper<SystemRole>().eq("code", RoleCodeEnum.GROUP_MEMBER.getCode()));
            SystemUserRoleDto urDto = new SystemUserRoleDto();
            urDto.setUserId(systemUsers.getId());
            urDto.setRoleId(role.getId());
            systemUserRoleService.saveSystemUserRole(urDto);
            String groupCode = systemUsersDto.getGroupCode();
            BadmintonGroup badmintonGroupByCode;
            if (systemUsersDto.getNewGroup() == 1) {
                BadmintonGroupDto param = new BadmintonGroupDto();
                param.setGroupName(systemUsersDto.getGroupName()==null?systemUsers.getUsername()+"注册群":systemUsersDto.getGroupName());
                param.setCreator(systemUsers.getId());
                param.setUpdater(systemUsers.getId());
                groupService.saveBadmintonGroup(param);
            }
            if (ObjectUtil.isNotNull(groupCode)) {
                badmintonGroupByCode = groupService.findBadmintonGroupByCode(groupCode);
                if (badmintonGroupByCode == null) {
                    ProjectException.newException(DB_DATA_NULL, "群不存在:" + groupCode);
                }
                ApplyJoinGroupDto applyJoinGroupDto = new ApplyJoinGroupDto();
                applyJoinGroupDto.setUserName(systemUsersDto.getGroupMemberName());
                applyJoinGroupDto.setGroupCode(groupCode);
                applyJoinGroupDto.setSex(systemUsersDto.getSex());

                ResponseRest responseRest = userGroupRefService.applyJoinGroup(applyJoinGroupDto);
                if (!responseRest.getSuc()) {
                    throw new ProjectException(responseRest.getCode(), responseRest.getMsg());
                }
            }
//        systemUsersVo.setPassword(null);//密码不返回给前端
            String[] array = new String[]{RoleCodeEnum.GROUP_ADMIN.getCode()};//当前群的权限
            UserDetails build = User.withUsername(systemUsersVo.getUsername()).password("").authorities(array).build();
            JwtTokenUtils.setToken(response, systemUsersVo, build);
        } catch (Exception e) {
            if (ObjectUtil.isNotEmpty(systemUsersVo)) {
                RedisUtil.toDelete(RedisEnum.badminton_user_info_name, systemUsersVo.getUsername());
            }
            throw e;
        }
        return systemUsersVo;
    }

    @Override
    public SystemUsersVo loginByPhone(String phone, String password, HttpServletResponse response) {
        SystemUsers byName = this.getOne(new QueryWrapper<SystemUsers>().eq("mobile", phone));
        if (isEmpty(byName)) {
            ProjectException.newException(RespCodeMessage.DB_DATA_NULL, "用户不存在");
        }
        if (!passwordEncoder.matches(password, byName.getPassword())) {
            ProjectException.newException(RespCodeMessage.SECURITY_PASSWORD_ERROR);
        }
        SystemUsersVo systemUsersVo = SystemUsersVo.invertToVo(byName);

        String[] array = new String[]{RoleCodeEnum.GROUP_ADMIN.getCode()};//当前群的权限
        UserDetails jwtUser = User.withUsername(systemUsersVo.getUsername()).password("").authorities(array).build();
//        List<BadmintonGroupVo> groupByUserId = groupService.findGroupByUserId(systemUsersVo.getId());
//        systemUsersVo.setGroupList(groupByUserId);
        JwtTokenUtils.setToken(response, systemUsersVo, jwtUser);
//        systemUsersVo.setPassword(null);//密码不返回给前端
        return systemUsersVo;
    }

    @Override
    public void updateLogin(SystemLoginLog systemLoginLog) {
        Long userId = systemLoginLog.getUserId();
        SystemUsers systemUsers = baseMapper.selectById(userId);
        systemUsers.setLoginDate(new Date());
        systemUsers.setLoginIp(systemLoginLog.getLoginIp());
        systemUsers.setPassword(null);
        this.updateSystemUsers(systemUsers);
    }


    private String generateUserCode() {
        String userCode = IdUtil.nanoId(8);
        while (this.getOne(new QueryWrapper<SystemUsers>().eq("user_code", userCode)) != null) {
            userCode = IdUtil.nanoId(8);
        }
        return userCode;
    }
}
